<?php 

error_reporting(E_ALL);
ini_set('display_errors', 'on');
define('TYPEHINT_PCRE' ,'/^Argument (\d)+ passed to (?:(\w+)::)?(\w+)\(\) must be an instance of (\w+), (\w+) given/');

class Typehint {
    private static $Typehints = array(
        'boolean'   => 'is_bool',
        'mixed'     => 'is_mixed',
        'integer'   => 'is_int',
        'float'     => 'is_float',
        'string'    => 'is_string',
        'resrouce'  => 'is_resource',
        'byte'      => 'is_byte'
    );

    private function __constrct() {}

    public static function initializeHandler() {
        set_error_handler( 'Typehint::handleTypehint' );

        return TRUE;
    }

    private static function getTypehintedArgument( $ThBackTrace, $ThFunction, $ThArgIndex, &$ThArgValue ) {
        foreach ( $ThBackTrace as $ThTrace ) {
            // Match the function; Note we could do more defensive error checking.
            if ( isset($ThTrace[ 'function' ] ) && $ThTrace[ 'function' ] == $ThFunction) {
                $ThArgValue = $ThTrace[ 'args' ][ $ThArgIndex - 1 ];
                return TRUE;
            }
        }

        return FALSE;
    }

    public static function handleTypehint( $ErrLevel, $ErrMessage ) {
        if ( $ErrLevel == E_RECOVERABLE_ERROR ) {
            if ( preg_match ( TYPEHINT_PCRE, $ErrMessage, $ErrMatches ) ) {
                list ( $ErrMatch, $ThArgIndex, $ThClass, $ThFunction, $ThHint, $ThType ) = $ErrMatches;
                if ( isset ( self::$Typehints [$ThHint] ) ) {
                    $ThBacktrace = debug_backtrace();
                    $ThArgValue = NULL;
                    if ( self::getTypehintedArgument ( $ThBacktrace, $ThFunction, $ThArgIndex, $ThArgValue ) ) {
                        if ( call_user_func( self::$Typehints[ $ThHint ], $ThArgValue ) ) {
                            return TRUE;
                        }
                    }
                }
                throw new Exception( $ErrMessage );
            }
        }
        return FALSE; 
    }
}
Typehint::initializeHandler();

function is_byte($value) {
    if (!is_int($value)) return false;
    if ($value < -128 || $value > 127) return false;
    return true;
}

function is_dbfield($value) {
    return Guardian::is_db_fieldname($value);
}

function is_mixed($value) {
    if ($value) return true;
}

function is_classname($value) {
    return __autoload($value);
}

?>